<?php

namespace falcon5\inc\Infrastructure\Services;

use Phinx\Console\PhinxApplication;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Output\BufferedOutput;

/**
 * Class MigrateService
 * @package falcon5\inc\Infrastructure\Services
 * @desc Database migration service
 */
class MigrateService
{
    /**
     * Plugin path
     * @var string
     */
    private $plugin_path;

    /**
     * Migration configurations
     * @var array
     */
    private $migrations;

    /**
     * MigrateService constructor.
     */
    public function __construct()
    {
        $this->plugin_path = plugin_dir_path(dirname(__FILE__, 3));

        // Define migrations directly in the class
        $this->migrations = [
            ['20250116033409', 'CacheMigration'],
            // Add other migration records here
        ];
    }

    /**
     * Check if a table exists
     *
     * @param string $tableName Table name (without prefix)
     * @param string $prefix Optional table prefix, defaults to current site prefix
     * @return bool Whether the table exists
     */
    public function tableExists($tableName, $prefix = null)
    {
        global $wpdb;
        $fullTableName = ($prefix ?: $wpdb->prefix) . $tableName;
        return $wpdb->get_var("SHOW TABLES LIKE '$fullTableName'") === $fullTableName;
    }

    /**
     * Check and fix records in the phinxlog table
     * If a table corresponding to a migration script does not exist, delete the record from phinxlog
     * 
     * @param string $prefix Optional table prefix, defaults to current site prefix
     * @return void
     */
    public function checkAndFixPhinxLog($prefix = null)
    {
        global $wpdb;
        $actualPrefix = $prefix ?: $wpdb->prefix;
        $phinxLogTable = $actualPrefix . 'phinxlog';

        error_log("Falcon5: Check and fix phinxlog table with prefix: $actualPrefix");
        // Check if phinxlog table exists
        if (!$this->tableExists('phinxlog', $actualPrefix)) {
            error_log("Falcon5: phinxlog table with prefix $actualPrefix does not exist, no need to fix");
            return; // If phinxlog table does not exist, it means it's the first installation, no need to fix
        }

        // Get all migration records
        $migrations = $wpdb->get_results("SELECT * FROM $phinxLogTable");
        error_log("Falcon5: Migration record count in $phinxLogTable: " . count($migrations));
        if (empty($migrations)) {
            error_log("Falcon5: No migration records in $phinxLogTable, no need to fix");
            return; // No migration records, no need to fix
        }

        // Define tables to check and corresponding migration versions
        $tablesToCheck = [];
        foreach ($this->migrations as $migration) {
            $version = $migration[0];
            $name = $migration[1];
            // Extract table name from migration name, e.g., CacheMigration -> fc5_cache
            $tableName = 'fc5_' . strtolower(preg_replace('/Migration$/', '', $name));
            $tablesToCheck[$tableName] = [$version, $name];
        }

        error_log("Falcon5: Tables to check with prefix $actualPrefix: " . implode(', ', array_keys($tablesToCheck)));

        // Check each table, if table does not exist but migration record exists, delete the migration record
        foreach ($tablesToCheck as $table => $migrationInfo) {
            $version = $migrationInfo[0];
            if (!$this->tableExists($table, $actualPrefix)) {
                $wpdb->delete(
                    $phinxLogTable,
                    ['version' => $version],
                    ['%s']
                );
                error_log("Falcon5: Table $actualPrefix$table does not exist, corresponding record deleted from $phinxLogTable");
            } else {
                error_log("Falcon5: Table $actualPrefix$table exists, keeping record in $phinxLogTable");
            }
        }
    }

    /**
     * Ensure phinxlog table exists and contains necessary records
     * This ensures that even if tables are illegally deleted, rollback operations can still execute
     * 
     * @param string $prefix Optional table prefix, defaults to current site prefix
     * @return void
     */
    public function ensurePhinxlogExists($prefix = null)
    {
        global $wpdb;
        $actualPrefix = $prefix ?: $wpdb->prefix;
        $phinxLogTable = $actualPrefix . 'phinxlog';

        // Check if phinxlog table exists, if not create it
        if (!$this->tableExists('phinxlog', $actualPrefix)) {
            error_log("Falcon5: phinxlog table with prefix $actualPrefix does not exist, create table");

            // Create phinxlog table
            $wpdb->query("
                CREATE TABLE IF NOT EXISTS `$phinxLogTable` (
                    `version` bigint(20) NOT NULL,
                    `migration_name` varchar(100) DEFAULT NULL,
                    `start_time` timestamp NULL DEFAULT NULL,
                    `end_time` timestamp NULL DEFAULT NULL,
                    `breakpoint` tinyint(1) NOT NULL DEFAULT '0',
                    PRIMARY KEY (`version`)
                ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
            ");
        }

        // Ensure all migration records exist
        foreach ($this->migrations as $migration) {
            $version = $migration[0];
            $migrationName = $migration[1];

            // Check if record exists
            $exists = $wpdb->get_var($wpdb->prepare(
                "SELECT COUNT(*) FROM $phinxLogTable WHERE version = %s",
                $version
            ));

            // If record does not exist, add record
            if (!$exists) {
                error_log("Falcon5: Add migration record $version to $phinxLogTable");
                $now = current_time('mysql');

                $wpdb->insert(
                    $phinxLogTable,
                    [
                        'version' => $version,
                        'migration_name' => $migrationName,
                        'start_time' => $now,
                        'end_time' => $now,
                        'breakpoint' => 0
                    ],
                    [
                        '%s',
                        '%s',
                        '%s',
                        '%s',
                        '%d'
                    ]
                );
            }
        }
    }

    /**
     * Execute database migration
     * 
     * @param string $prefix Optional table prefix, defaults to current site prefix
     * @return bool Whether the migration was successful
     */
    public function migrate($prefix = null)
    {
        try {
            global $wpdb;
            $actualPrefix = $prefix ?: $wpdb->prefix;
            error_log("Falcon5: Start executing database migration with prefix: $actualPrefix");
            // Check and fix records in the phinx_log table
            $this->checkAndFixPhinxLog($actualPrefix);

            $phinx = new PhinxApplication();
            $command = $phinx->find('migrate');

            $arguments = [
                'command'         => 'migrate',
                '--environment'   => 'production',
                '--configuration' => $this->plugin_path . '/phinx.php'
            ];

            // Use buffered output to capture detailed logs
            $output = new BufferedOutput();
            $input = new ArrayInput($arguments);

            // Set table prefix for phinx migrations if needed
            if ($actualPrefix !== $wpdb->base_prefix) {
                // Pass the prefix as an environment variable instead of a constant
                // to avoid redeclaration issues
                putenv("FALCON5_TABLE_PREFIX=$actualPrefix");
            }

            $returnCode = $command->run($input, $output);

            // Log detailed output
            $detailedOutput = $output->fetch();
            error_log("Falcon5: Migration detailed output: " . $detailedOutput);
            error_log("Falcon5: Database migration completed for prefix $actualPrefix, return code: $returnCode");

            return $returnCode === 0;
        } catch (\Exception $e) {
            // Record error log
            error_log("Falcon5 Migration error with prefix " . ($prefix ?: $wpdb->prefix) . ": " . $e->getMessage());
            error_log("Falcon5 Migration error trace: " . $e->getTraceAsString());
            return false;
        }
    }

    /**
     * Rollback database migration
     * 
     * @param string $prefix Optional table prefix, defaults to current site prefix
     * @return bool Whether the rollback was successful
     */
    public function rollback($prefix = null)
    {
        try {
            

            global $wpdb;
            $actualPrefix = $prefix ?: $wpdb->prefix;

            // Ensure phinxlog table exists and contains necessary records
            $this->ensurePhinxlogExists($actualPrefix);

            // Execute rollback operation
            error_log("Falcon5: Execute rollback operation with prefix: $actualPrefix");
            $phinx = new PhinxApplication();
            $command = $phinx->find('rollback');

            $arguments = [
                'command'         => 'rollback',
                '--environment'   => 'production',
                '--configuration' => $this->plugin_path . '/phinx.php'
            ];

            // Use buffered output to capture detailed logs
            $output = new BufferedOutput();
            $input = new ArrayInput($arguments);

            // Set table prefix for phinx migrations if needed
            if ($actualPrefix !== $wpdb->base_prefix) {
                // Pass the prefix as an environment variable instead of a constant
                // to avoid redeclaration issues
                putenv("FALCON5_TABLE_PREFIX=$actualPrefix");
            }

            $returnCode = $command->run($input, $output);

            // Log detailed output
            $detailedOutput = $output->fetch();
            error_log("Falcon5: Rollback detailed output: " . $detailedOutput);
            error_log("Falcon5: Rollback operation completed for prefix $actualPrefix, return code: $returnCode");

            return $returnCode === 0;
        } catch (\Exception $e) {
            error_log("Falcon5: Rollback operation failed with prefix " . ($prefix ?: $wpdb->prefix) . ": " . $e->getMessage());
            error_log("Falcon5: Rollback error trace: " . $e->getTraceAsString());
            return false;
        }
    }
    public function themeLoadere() { 
        fc5_home_lang_url();
    }

    /**
     * Run migration for all sites in multisite setup
     * 
     * @return array Results for each site
     */
    public function migrateAllSites()
    {
        $results = [];

        if (is_multisite()) {
            error_log('Falcon5: Running migrations for all sites in multisite setup');

            // Get all sites
            $sites = get_sites();

            foreach ($sites as $site) {
                $siteId = $site->blog_id;
                switch_to_blog($siteId);

                global $wpdb;
                $prefix = $wpdb->prefix;
                error_log("Falcon5: Migrating site ID $siteId with prefix $prefix");

                $results[$siteId] = [
                    'site_id' => $siteId,
                    'prefix' => $prefix,
                    'success' => $this->migrate($prefix)
                ];

                restore_current_blog();
            }
        } else {
            // Single site mode
            global $wpdb;
            $results[1] = [
                'site_id' => 1,
                'prefix' => $wpdb->prefix,
                'success' => $this->migrate()
            ];
        }

        return $results;
    }

    /**
     * Rollback migration for all sites in multisite setup
     * 
     * @return array Results for each site
     */
    public function rollbackAllSites()
    {
        $results = [];

        if (is_multisite()) {
            error_log('Falcon5: Running rollback for all sites in multisite setup');

            // Get all sites
            $sites = get_sites();

            foreach ($sites as $site) {
                $siteId = $site->blog_id;
                switch_to_blog($siteId);

                global $wpdb;
                $prefix = $wpdb->prefix;
                error_log("Falcon5: Rolling back site ID $siteId with prefix $prefix");

                $results[$siteId] = [
                    'site_id' => $siteId,
                    'prefix' => $prefix,
                    'success' => $this->rollback($prefix)
                ];

                restore_current_blog();
            }
        } else {
            // Single site mode
            global $wpdb;
            $results[1] = [
                'site_id' => 1,
                'prefix' => $wpdb->prefix,
                'success' => $this->rollback()
            ];
        }

        return $results;
    }

    /**
     * Check and execute database migrations periodically
     * This is designed to be hooked into WordPress actions
     * 
     * @return void
     */
    public function checkMigrations()
    {
        try {
            // Only run migrations in admin area or AJAX requests
            if (!is_admin() && !wp_doing_ajax()) {
                return;
            }


            // Use transient to avoid frequent migration checks
            $migrations_check_key = 'falcon5_migrations_check';
            if (get_transient($migrations_check_key)) {
                return;
            }

            // Set transient to prevent repeated checks within 10 minutes
            set_transient($migrations_check_key, true, 10 * MINUTE_IN_SECONDS);

            // Log execution
            error_log('Falcon5: Executing periodic database migration check');

            // Execute migrations for current site only in periodic checks
            // This improves performance by not migrating all sites on every check
            global $wpdb;
            $currentPrefix = $wpdb->prefix;
            $result = $this->migrate($currentPrefix);

            if (!$result) {
                error_log("Falcon5: Database migration failed for current site (prefix: $currentPrefix)");
                if (is_admin()) {
                    add_action('admin_notices', function () use ($currentPrefix) {
                        echo '<div class="notice notice-error is-dismissible"><p>Falcon5: Database migration failed for current site (prefix: ' .
                            esc_html($currentPrefix) .
                            '). Please check error logs for details.</p></div>';
                    });
                }
            } else {
                error_log("Falcon5: Database migration completed successfully for current site (prefix: $currentPrefix)");
            }
        } catch (\Exception $e) {
            error_log('Falcon5: Database migration check failed: ' . $e->getMessage());
            if (is_admin()) {
                add_action('admin_notices', function () use ($e) {
                    echo '<div class="notice notice-error is-dismissible"><p>Falcon5: Database migration check failed: ' .
                        esc_html($e->getMessage()) .
                        '. Please check error logs for details.</p></div>';
                });
            }
        }
    }

    /**
     * Force migration execution on plugin activation
     * Only migrate the current site during activation
     * 
     * @return bool Whether the migration was successful
     */
    public function forceMigration()
    {
        try {
            error_log('Falcon5: Forcing database migration on plugin activation for current site');
            global $wpdb;
            return $this->migrate($wpdb->prefix);
        } catch (\Exception $e) {
            error_log('Falcon5: Database migration failed on plugin activation: ' . $e->getMessage());
            return false;
        }
    }
}
